#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<assert.h>
#include<cmath>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<stack>
using namespace std;
const int inf=1000000000;
const double pi=acos(-1.0);
#define eps (1e-15)
#define L(x) ((x)<<1)
#define R(x) ((x)<<1|1)
#define see(x)(cerr<<"[line:"<<__LINE__<<" "<<#x<<" "<<x<<endl)
#define se(x) cerr<<x<<" "
template<class T>T& ls(T& a,T b)
{ if(b<a) a=b; return a;}
template<class T>T& gs(T& a,T b)
{ if(b>a) a=b; return a;}
inline int to_i(const string& s)
{int n;sscanf(s.c_str(),"%d",&n);return n;}
inline string to_s(int n)
{char buf[32];sprintf(buf,"%d",n);return string(buf);}
inline int get(){int x;scanf("%d",&x);return x;}
int n,m;
const int maxn = 522222;
int cnt=0;
int a[maxn];
/**********splay模板****************/
#define key (ne[ne[root][1] ][0])
template<int maxv>
struct Splay{
	int ne[maxv][2],sz[maxv],pre[maxv];//ne是左右儿子，sz是树的大小,pre是父亲
	int ss[maxv],que[maxv];//ss是栈内存，que是队列
	int root,top1,top2;// root是根，top1是队列，top2是栈
	
	inline void rotate(int x,int c)
	{
		int y=pre[x];
		pushdown(y);
		pushdown(x);
		ne[y][!c]=ne[x][c];
		pre[ ne[x][c] ] =y; 
		pre[x]=pre[y];
		if(pre[x]) ne[pre[y]][ne[pre[y]][1] == y]=x;
		ne[x][c]=y;
		pre[y]=x;
		pushup(y);
	}
	inline void splay(int x,int go)
	{//把x转到goal下面
		pushdown(x);
		while(pre[x]!=go)
		{
			if(pre[pre[x]]==go)//x的父亲的父亲是目标
				rotate(x, ne[pre[x]][0]==x);
			else
			{
				int y=pre[x],z=pre[y];
				int c=(ne[z][0]==y);
				if(ne[y][c]==x)//判断是之字还是一字
					rotate(x,!c),rotate(x,c);
				else
					rotate(y,c),rotate(x,c);
			}			
		}
		pushup(x);
		if(go==0)	root=x;
	}
	inline void rotateto(int k,int go)//把第k位的数转到goal下边
	{//原来第k位的数是中序遍历第k+1个节点
//注意因为加了一个左边的最小值所以才可以用这个函数,实际上返回splay第k+1大的元素
//也就是树从root中序遍历第k+1个节点旋到根。
		int x=root;
		pushdown(x);
		while(sz[ne[x][0]]!=k)
		{
			if(k< sz[ne[x][0]] )
				x=ne[x][0];
			else
			{
				k-=(sz[ne[x][0]]+1);
				x=ne[x][1];
			}
			pushdown(x);
		}
		splay(x,go);
	}
	
	inline void erase(int x)//把以x为祖先结点删掉放进内存池,回收内存
	{
		int head=0,tail=0;
		for(que[tail++]=x; head<tail; head++)
		{
			ss[top2++]=	que[head];
			if(ne[ que[head ]][0])  que[tail++]= ne[que[head]][0];
			if(ne[ que[head ]][1])  que[tail++]= ne[que[head]][1];
		}
	}
	/* getEnd(x,c): 得到x节点最边缘的节点 c=0-最左边的 c=1-最右边的 */
	inline int getend(int x,int c)
	{
		while(ne[x][c])
		{
			pushdown(x);
			x=ne[x][c];
		}
		return x;
	}
    /* getNear(x,c): 得到x节点最近的节点 c=0-前驱节点 c=1-后继节点 */
	inline int getnear(int x,int c)
	{
		if(ne[x][c])
			return getend(ne[x][c],1-c);
		while(pre[x]&& ne[pre[x]][c]==x)
			x=pre[x];
		return pre[x];
	}
	
	/* getsuc(x): 得到x节点的后继节点 */
	inline int getsuc(int x){return getnear(x,1);}
	
	/* getpre(x): 得到x节点的前驱节点 */
	inline int getpre(int x){return getnear(x,0);}
	
	inline void getson(int x,int &l,int &r)
	{
		l=ne[x][0];
		r=ne[x][1];
	}
	/************以上基本不变****END**********************/
	/****************debug**********************/
	void debug()
	{
		cnt=0;
		printf("%d\n",root); travel(root);
	}
	void travel(int x)
	{
		if(x)	
		{
			pushdown(x);
		printf("rt:%d l:%d r:%d pre:%d sz%d val%d\n",x,ne[x][0],ne[x][1],pre[x],sz[x],val[x]);
			travel(ne[x][0]);
			a[cnt++]=val[x];	
			travel(ne[x][1]);
		}
	}
	//以上调试
	/****************END**********************/
	
	//把孩子s状态更新上来
	inline void pushup(int x)
	{
		sz[x]=1+sz[ne[x][0]]+sz[ne[x][1]];
	 /******* 题目的特定函数内容 **********/
		
		int l,r;getson(x,l,r);
		sum[x]=add[x]+val[x]+sum[l] +sum[r];
		
		minnode[x]=x;
		if(l && cmp(minnode[l],minnode[x]) )
			minnode[x]=minnode[l];
		if(r && cmp(minnode[r],minnode[x]) )
			minnode[x]=minnode[r];
/*****由于0节点加了-inf，让maxl,maxr,maxm都可能取到0节点，注意下面可能有l或者r取0的情况，用这种方法可以特殊处理***/
        maxl[x]=max(maxl[l],sum[l]+val[x]+max(0,maxl[r]));
        maxr[x]=max(maxr[r],sum[r]+val[x]+max(0,maxr[l]));

        maxm[x]=max(maxm[l],maxm[r]);
        maxm[x]=max(maxm[x],max(0,maxr[l])+val[x]+max(0,maxl[r]));
	}
	//把延迟标记推到孩子
	inline void pushdown(int x)
	{
		if(x)
		{
			if(add[x])
			{
				val[x]+=add[x];
				for(int i=0; i<2; i++)
				{
					add[ne[x][i]]+=add[x];
					sum[ne[x][i]]+=(int )sz[ne[x][i]]*add[x];
				}
				add[x]=0;
			}
			if(isrev[x])
			{
				int l,r;getson(x,l,r);
				revnode(l);
				revnode(r);
				isrev[x]=0;
			}
			if(same[x][0])
			{
				int l,r;getson(x,l,r);
				samenode(l,same[x][1]);
				samenode(r,same[x][1]);
				same[x][0]=same[x][1]=0;
			}
		}
	}
	/*初始化*/
	inline void maketree(int &x,int l,int r,int c)
	{//x是当前节点，l，r是数列,c是father
		if(l>r)	return ;
		int mid=(l+r)/2;
		newnode(x,a[mid]);
		maketree(ne[x][0], l,mid-1,x);
		maketree(ne[x][1],mid+1,r,x);
		pre[x]=c;
		pushup(x);
	}
		//以下是题目的特定函数:
	inline void newnode(int &x,int c)//x会自己赋值的
	{//用栈手动压的内存池
		if(top2) x=ss[--top2];
		else x=++top1;
		ne[x][0]=ne[x][1]=pre[x]=0;
		sz[x]=1;
	/*这是题目特定函数*/
		minnode[x]=x;
		add[x]=isrev[x]=same[x][0]=same[x][1]=0;
		val[x]=c;
		sum[x]=maxl[x]=maxm[x]=maxr[x]=c;	
	}
	inline void init(int n)
	{
		ne[0][0]=ne[0][1]=pre[0]=sz[0]=0;//0要特别输出化，所有的空节点都指向0
		/****题目特定赋值********/
		val[0]=add[0]=isrev[0]=same[0][0]=same[0][1]=0;
		sum[0]=0 ;	
		//下面这个地方之所以要这么处理，是因为pushup里面的跟新为了节省代码，但是不能判左右儿子是否存在，所以这样构造就可以不选0号节点，0号节点是所以无儿子节点的儿子节点
		maxr[0]=maxl[0]=maxm[0]=-inf;
		
		root=top1=top2=0;
		
		//为了方便处理边界,加两个边界顶点
		/* 增加第一个边界结点 */
		newnode(root,0);//root是最左边点 最后root是1
		/* 增加第二个边界结点 */
		newnode(ne[root][1],0);//ne[root][1]是最右边点
		pre[top1]=root;//root现在是0，top1现在是1
		sz[root]=2;
		
		maketree(key,1,n,ne[root][1]);
		pushup(ne[root][1]);//注意更新
		pushup(root);//注意更新
	}
	/********旋转操作******************/
	inline void revnode(int x)//把x旋转
	{
		if(x)
		{
			isrev[x]^=1;
			swap(ne[x][0],ne[x][1]);
			swap(maxl[x],maxr[x]);//注意这个关系改变了
		}
	}
	/********赋值操作******************/
	inline void samenode(int x,int y)//把x为根的数每个节点值都赋值为y
	{
		if(x)
		{
			val[x]=y;
			sum[x]=y*sz[x];
			maxm[x]=maxl[x]=maxr[x]=max(val[x],sum[x]);
			same[x][0]=1;
			same[x][1]=y;
		}
	}
	inline void query(int x)//hdu 1890 的操作
	{
		int i,minn=1;
		int succ;
		for(i=0; i<n-1; i++)
		{
			splay(minn,0);
			minn=minnode[ne[root][1]];
			splay(minn,root);
			succ=getsuc(minn);
			splay(succ,root);
			printf("%d ",i+sz[key]);
			revnode(key);
		}
		printf("%d\n",n);
	}
	
	inline void cut(int x,int y,int z)//hdu3487 cut操作 
	{
		int i,j;
		rotateto(x-1,0);
		rotateto(y+1,root);
		int now=key;
		key=0;
		rotateto(z,0);
		rotateto(z+1,root);
		insert(now,ne[root][1]);
		pushup(root);
	}
	inline void reverse(int x,int y)//hdu3487 FLIP操作
	{//把数列第x位置到第y位置翻转
		rotateto(x-1,0);
		rotateto(y+1,root);
		revnode(key);
	}
	inline void update()//加上某个值的操作
	{
		int l,r,c;
		scanf("%d%d%d",&l,&r,&c);
		rotateto(l-1,0);//0下面就是根
		rotateto(r+1,root);
		add[key]+=c;
		sum[key]+=(int )sz[key]*c;
	}
	inline int  getsum(int x,int y)//得到数列[x,y]的和
	{
		rotateto(x-1,0);
		rotateto(y+1,root);
		return sum[key];
	}
	inline int  maxsum(int x,int y)//得到数列[x,y]的连续区间最大的和
	{
		rotateto(x-1,0);
		rotateto(y+1,root);
		return maxm[key];
	}
	inline void  inserttree(int x,int k)//在第x位，插入的树大小为k
	{
		rotateto(x,0);
		rotateto(x+1,root);
		maketree(key,1,k,ne[root][1]);
		pushup(ne[root][1]);
       	pushup(root);
	}
	inline void del(int x,int y)//删除数列[x,y]的数
	{
		rotateto(x-1,0);
		rotateto(y+1,root);
		erase(key);
		key=0;
		pushup(ne[root][1]);
        pushup(root);
	}
	inline void makesame(int x,int y,int z)//把数列[x,y]的每个数改变为z
	{
		rotateto(x-1,0);
		rotateto(y+1,root);
		samenode(key,z);
		pushup(ne[root][1]);
        pushup(root);
	}
	/****************************/
	inline int cmp(int a,int b)
	{	return val[a]<val[b]; } 
	 /* Optional Variables 题目不同，变量不同 */
	int minnode[maxv];//求最小的标号在哪里的函数
	int val[maxv],add[maxv],isrev[maxv],same[maxv][2];
	int  sum[maxv],maxl[maxv],maxm[maxv],maxr[maxv];
};
Splay<maxn>sp;
char ch[1010];
int main()
{
#ifndef ONLINE_JUDGE
	freopen("in","r",stdin);
#endif
    int i,j,k,t;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		int x,y,z;
		for(i=1; i<=n; i++)
			a[i]=get();
		sp.init(n);
		//sp.debug();
		for(i=0; i<m; i++)
		{
			scanf("%s",ch);
			if(ch[0]=='G')//	GET-SUM 5 4
			{
				x=get();y=get();
				int ans=sp.getsum(x,x+y-1);
				printf("%d\n",ans);
			}
			else if(ch[0]=='M' &&ch[2]=='X')//MAX-SUM
			{
				x=get();y=get();
				int ans=sp.maxsum(1,sp.sz[sp.root]-2);
				printf("%d\n",ans);
			}
			else if(ch[0]=='I')//INSERT 8 3 -5 7 2
			{
				x=get();y=get();
				for(j=1; j<=y; j++)
				{
					scanf("%d",a+j);
				}
				n+=y;
				sp.inserttree(x,y);
			}
			else if(ch[0]=='D')//DELETE 12 1
			{
				n-=y;
				x=get(); y=get();y=x+y-1;
				sp.del(x,y);
			}
			else if(ch[0]=='M'&&  ch[2]=='K')//MAKE-SAME 3 3 2
			{
				x=get(); y=get(); z=get();
				y=x+y-1;
				sp.makesame(x,y,z);
			}
			else if(ch[0]=='R')//REVERSE 3 6
			{
				x=get(); y= get();y=x+y-1;
				sp.reverse(x,y);
			}
		}
	}
}
